home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 October
/
EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso
/
Aminet
/
gfx
/
show
/
amipeg04.lha
/
aMiPEG_0.4
/
video.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-22
|
56KB
|
2,099 lines
/*
* This file contains C code that implements the video decoder model.
*/
#include "video.h"
#include "proto.h"
#include "decoders.h"
#include "util.h"
#include <time.h>
#define MYRECON
/* Declarations of functions. */
//static void init_stat_struct(Statval *);
//static void PrintOneStat(void);
//static void CollectStats(void);
//static unsigned int bitCountRead(void);
//static void StartTime(void);
//static void EndTime(void);
static int ParseSeqHead(VidStream *);
static int ParseGOP(VidStream *);
static int ParsePicture(VidStream *, TimeStamp);
static int ParseSlice(VidStream *);
static int ParseMacroBlock(VidStream *);
static void DoPictureDisplay(VidStream *);
#ifndef MYRECON
static void ReconIMBlock(VidStream *, int);
static void ReconPMBlock(VidStream *, int, int, int, int);
static void ReconBMBlock(VidStream *, int, int, int, int);
static void ReconBiMBlock(VidStream *, int, int, int, int, int, int);
#endif
static void ProcessSkippedPFrameMBlocks(VidStream *);
static void ProcessSkippedBFrameMBlocks(VidStream *);
static void ReconSkippedBlock16(unsigned char *, unsigned char *, int, int, int, int, int, int, int);
static void ReconSkippedBlock8(unsigned char *, unsigned char *, int, int, int, int, int, int, int);
extern int ditherType;
/* Macro for returning 1 if num is positive, -1 if negative, 0 if 0. */
//#define Sign(num) ((num > 0) ? 1 : ((num == 0) ? 0 : -1))
/* Declare global pointer to vid stream used for current decoding. */
VidStream *curVidStream = NULL;
/* Array mapping zigzag to array pointer offset. */
int zigzag_direct[64] = {
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12,
19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63};
/* Initialize P and B skip flags. */
static int No_P_Flag = 0;
static int No_B_Flag = 0;
/* Max lum, chrom indices for illegal block checking. */
static int lmaxx, lmaxy, cmaxx, cmaxy;
/*
The following accounts for time and size spent in various parsing acitivites
if ANALYSIS has been defined.
*/
#ifdef ANALYSIS
#include "analysis.h"
#endif
double realTimeStart;
int totNumFrames = 0;
double ReadSysClock(void)
{
unsigned int clock[2];
(void) timer(clock);
return clock[0] + clock[1] / 1000000.0;
}
void PrintTimeInfo(void)
{
if (!quietFlag) {
double spent = ReadSysClock() - realTimeStart;
printf("\nReal Time Spent (After Initializations): %f secs.\n", spent);
printf("Avg. Frames/Sec: %f\n", ((double) totNumFrames) / spent);
printf("Frame size: %i*%i pixels\n", curVidStream->h_size, curVidStream->v_size);
}
}
/*
*--------------------------------------------------------------
*
* NewVidStream --
*
* Allocates and initializes a VidStream structure. Takes
* as parameter requested size for buffer length.
*
* Results:
* A pointer to the new VidStream structure.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
VidStream * NewVidStream(int bufLength)
{
int i,j;
short *intra_quant_matrix, *intra_quant_matrix0, *intra_quant_matrix1;
VidStream *new;
static unsigned char default_intra_matrix[64] = {
8, 16, 19, 22, 26, 27, 29, 34,
16, 16, 22, 24, 27, 29, 34, 37,
19, 22, 26, 27, 29, 34, 34, 38,
22, 22, 26, 27, 29, 34, 37, 40,
22, 26, 27, 29, 32, 35, 40, 48,
26, 27, 29, 32, 35, 40, 48, 58,
26, 27, 29, 34, 38, 46, 56, 69,
27, 29, 35, 38, 46, 56, 69, 83};
/* Check for legal buffer length. */
if (bufLength < 4) return NULL;
/* Make buffer length multiple of 4. */
bufLength = (bufLength + 3) >> 2;
/* Allocate memory for new structure. */
new = (VidStream *) malloc(sizeof(VidStream));
/* Initialize pointers to extension and user data. */
new->group.ext_data = new->group.user_data =
new->picture.extra_info = new->picture.user_data =
new->picture.ext_data = new->slice.extra_info =
new->ext_data = new->user_data = NULL;
/* Create default intra matrix and qscale multiplication tables. */
new->intra_quant_matrix_ptr[0] = (short*) malloc(32 * 8*8 * sizeof(short));
clear64words(intra_quant_matrix = new->intra_quant_matrix_ptr[0]);
for(j=1; j<32; j++) new->intra_quant_matrix_ptr[j] = (intra_quant_matrix+=64);
intra_quant_matrix0 = intra_quant_matrix = new->intra_quant_matrix_ptr[1];
for(i=0; i<64; i++)
*intra_quant_matrix++ = default_intra_matrix[zigzag_direct[i]];
for(j=2; j<32; j++)
{
intra_quant_matrix1 = new->intra_quant_matrix_ptr[1];
for(i=0; i<64; i++) *intra_quant_matrix++ = (*intra_quant_matrix0++) + (*intra_quant_matrix1++);
}
/* Initialize non intra quantization matrix. */
new->non_intra_default = TRUE;
new->non_intra_quant_matrix_ptr[0] = NULL;
/* Initialize pointers to image spaces. */
new->current = new->past = new->future = NULL;
for (i = 0; i < RING_BUF_SIZE; i++) new->ring[i] = NULL;
/* Create buffer. */
new->buf_start = (unsigned int *) malloc(bufLength * 4);
/*
* Set max_buf_length to one less than actual length to deal with messy
* data without proper seq. end codes.
*/
new->max_buf_length = bufLength - 1;
/* Initialize bitstream i/o fields. */
new->bit_offset = 0;
new->buf_length = 0;
new->buffer = new->buf_start;
/* display stuff */
new->display_is_initialized = FALSE;
/* Return structure. */
return new;
}
/*
*--------------------------------------------------------------
*
* DestroyVidStream --
*
* Deallocates a VidStream structure.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void DestroyVidStream(VidStream *astream)
{
int i;
if (astream->ext_data) free(astream->ext_data);
if (astream->user_data) free(astream->user_data);
if (astream->group.ext_data) free(astream->group.ext_data);
if (astream->group.user_data) free(astream->group.user_data);
if (astream->picture.extra_info) free(astream->picture.extra_info);
if (astream->picture.ext_data) free(astream->picture.ext_data);
if (astream->picture.user_data) free(astream->picture.user_data);
if (astream->slice.extra_info) free(astream->slice.extra_info);
if (astream->buf_start) free(astream->buf_start);
for (i = 0; i < RING_BUF_SIZE; i++) {
if (astream->ring[i]) {
DestroyPictImage(astream->ring[i]);
astream->ring[i] = NULL;
}
}
if (!astream->non_intra_default) free(astream->non_intra_quant_matrix_ptr[0]);
if (astream->intra_quant_matrix_ptr[0]) free(astream->intra_quant_matrix_ptr[0]);
free((char *) astream);
}
/*
*--------------------------------------------------------------
*
* NewPictImage --
*
* Allocates and initializes a PictImage structure.
* The width and height of the image space are passed in
* as parameters.
*
* Results:
* A pointer to the new PictImage structure.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
PictImage * NewPictImage(unsigned int width, unsigned int height)
{
extern int lores, ham6;
PictImage *new;
int size = (short)width * (short)height;
/* Allocate memory space for new structure. */
new = (PictImage *) malloc(sizeof(PictImage));
/* Allocate memory for image spaces. */
if (ditherType == FULL_COLOR_DITHER) {
new->display = (unsigned char *) malloc(ham6 ? size : (lores ? (size << 1) : (size << 2)));
} else {
new->display = (unsigned char *) malloc(size);
}
new->luminance = (unsigned char *) malloc(size);
new->Cr = (unsigned char *) malloc(size >> 2);
new->Cb = (unsigned char *) malloc(size >> 2);
/* Reset locked flag. */
new->locked = 0;
/* Return pointer to new structure. */
return new;
}
/*
*--------------------------------------------------------------
*
* DestroyPictImage --
*
* Deallocates a PictImage structure.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void DestroyPictImage(PictImage *apictimage)
{
if (apictimage->luminance) free(apictimage->luminance);
if (apictimage->Cr) free(apictimage->Cr);
if (apictimage->Cb) free(apictimage->Cb);
if (apictimage->display) free(apictimage->display);
free(apictimage);
}
/*
*--------------------------------------------------------------
*
* mpegInitVidRsrc --
*
* reset first to 1
*
* gonna check this thingy out !!!!
*
*--------------------------------------------------------------
*/
static int first = 1;
void mpegInitVidRsrc(void)
{
first = 1;
}
/*
*--------------------------------------------------------------
*
* mpegVidRsrc --
*
* Parses bit stream until MB_QUANTUM number of
* macroblocks have been decoded or current slice or
* picture ends, whichever comes first. If the start
* of a frame is encountered, the frame is time stamped
* with the value passed in time_stamp. If the value
* passed in buffer is not null, the video stream buffer
* is set to buffer and the length of the buffer is
* expected in value passed in through length. The current
* video stream is set to vid_stream. If vid_stream
* is passed as NULL, a new VidStream structure is created
* and initialized and used as the current video stream.
*
* Results:
* A Boolean value is returned - 0 is end of picture or error
*
* Side effects:
* Bit stream is irreversibly parsed. If a picture is completed,
* a function is called to display the frame at the correct time.
*
*--------------------------------------------------------------
*/
int mpegVidRsrc(TimeStamp time_stamp, VidStream *vid_stream)
{
unsigned int data;
int i, status;
/* If vid_stream is null, create new VidStream structure. MR: ????? */
if (vid_stream == NULL) return 0;
/*
* Set global curVidStream to vid_stream. Necessary because bit i/o use
* curVidStream and are not passed vid_stream. Also set global bitstream
* parameters.
*/
curVidStream = vid_stream;
bitOffset = curVidStream->bit_offset;
bufLength = curVidStream->buf_length;
bitBuffer = curVidStream->buffer;
/*
* If called for the first time, find start code, make sure it is a
* sequence start code.
*/
if (first) {
next_start_code();
if (show_bits32(data) != SEQ_START_CODE) {
fprintf(stderr, "This is not an MPEG stream.\n");
DestroyVidStream(curVidStream);
exit(1);
}
first = 0;
}
/*
* Process according to start code (or parse macroblock if not a start code
* at all.
*/
switch (show_bits32(data)) {
case SEQ_END_CODE:
/* Display last frame. */
if (vid_stream->future != NULL) {
vid_stream->current = vid_stream->future;
ExecuteDisplay(vid_stream);
}
/* Sequence done. Do the right thing. return False. */
if (!quietFlag) {
fprintf(stderr, "\nDone!\n");
}
#ifdef ANALYSIS
PrintAllStats();
#endif
PrintTimeInfo();
if (loopFlag) longjmp(env, 1);
DestroyVidStream(curVidStream);
return 0;
break;
case SEQ_START_CODE:
/* Sequence start code. Parse sequence header. */
if (ParseSeqHead(vid_stream) != PARSE_OK) goto error;
/*
* Return after sequence start code so that application above can use
* info in header.
*/
goto done;
case GOP_START_CODE:
/* Group of Pictures start code. Parse gop header. */
if (ParseGOP(vid_stream) != PARSE_OK) goto error;
case PICTURE_START_CODE:
/* Picture start code. Parse picture header and first slice header. */
status = ParsePicture(vid_stream, time_stamp);
if (status == SKIP_PICTURE) {
next_start_code();
fprintf(stderr, "Skipping picture...");
while ((show_bits32(data)) != PICTURE_START_CODE) {
if (data == GOP_START_CODE || data == SEQ_END_CODE)
break;
flush_bits(24);
next_start_code();
}
fprintf(stderr, "Done.\n");
goto done;
} else if (status != PARSE_OK) goto error;
if (ParseSlice(vid_stream) != PARSE_OK) goto error;
break;
case USER_START_CODE: // there has been one stream with an error in a GOP header
flush_bits32;
if (vid_stream->group.user_data) {
free(vid_stream->group.user_data);
vid_stream->group.user_data = NULL;
}
vid_stream->group.user_data = get_ext_data();
break;
case EXT_START_CODE:
flush_bits32;
if (vid_stream->group.ext_data) {
free(vid_stream->group.ext_data);
vid_stream->group.ext_data = NULL;
}
vid_stream->group.ext_data = get_ext_data();
break;
default:
/* Check for slice start code. */
if ((data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE))
if (ParseSlice(vid_stream) != PARSE_OK) /* Slice start code. Parse slice header. */
goto error;
break;
}
/* Parse next MB_QUANTUM macroblocks. */
for (i = 0; i < MB_QUANTUM; i++) {
/* Check to see if actually a startcode and not a macroblock. */
if ((show_bitsn(23,data)) != 0x00000000) {
/* Not start code. Parse Macroblock. */
if (ParseMacroBlock(vid_stream) != PARSE_OK)
goto error;
#ifdef ANALYSIS
if (showmb_flag) {
DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr,
vid_stream->current->Cb, vid_stream->current->display,
vid_stream->mb_height * 16, vid_stream->mb_width * 16);
ExecuteDisplay(vid_stream);
}
#endif
} else {
/* Not macroblock, actually start code. Get start code. */
next_start_code();
show_bits32(data);
/*
* If start code is outside range of slice start codes, frame is
* complete, display frame.
*/
if ((data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE)) {
#ifdef ANALYSIS
EndTime();
stat_a[0].totsize += bitCountRead() - pictureSizeCount;
if (showEachFlag)
PrintOneStat();
CollectStats();
#endif
DoPictureDisplay(vid_stream);
}
break;
}
}
/* Return pointer to video stream structure. */
goto done;
error:
fprintf(stderr, "Error!!!!\n");
next_start_code();
goto done;
done:
/* Copy global bit i/o variables back into vid_stream. */
vid_stream->buffer = bitBuffer;
vid_stream->buf_length = bufLength;
vid_stream->bit_offset = bitOffset;
return 1;
}
/*
*--------------------------------------------------------------
*
* ParseSeqHead --
*
* Assumes bit stream is at the begining of the sequence
* header start code. Parses off the sequence header.
*
* Results:
* Fills the vid_stream structure with values derived and
* decoded from the sequence header. Allocates the pict image
* structures based on the dimensions of the image space
* found in the sequence header.
*
* Side effects:
* Bit stream irreversibly parsed off.
*
*--------------------------------------------------------------
*/
static int ParseSeqHead(VidStream *vid_stream)
{
unsigned int data;
int i;
/* Flush off sequence start code. */
flush_bits32;
/* Get horizontal size of image space. */
get_bits12(vid_stream->h_size);
/* Get vertical size of image space. */
get_bits12(vid_stream->v_size);
/* Calculate macroblock width and height of image space. */
vid_stream->mb_width = (vid_stream->h_size + 15) >> 4;
vid_stream->mb_height = (vid_stream->v_size + 15) >> 4;
/* Initialize lmaxx, lmaxy, cmaxx, cmaxy. */
lmaxx = (vid_stream->mb_width<<4)-1;
lmaxy = (vid_stream->mb_height<<4)-1;
cmaxx = (vid_stream->mb_width<<3)-1;
cmaxy = (vid_stream->mb_height<<3)-1;
/*
* Initialize ring buffer of pict images now that dimensions of image space
* are known.
*/
if (vid_stream->ring[0] == NULL) {
for (i = 0; i < RING_BUF_SIZE; i++)
vid_stream->ring[i] = NewPictImage(vid_stream->mb_width << 4, vid_stream->mb_height << 4);
}
/* Parse of aspect ratio code. */
get_bits4(vid_stream->aspect_ratio);
/* Parse off picture rate code. */
get_bits4(vid_stream->picture_rate);
/* Parse off bit rate. */
get_bits18(vid_stream->bit_rate);
/* Flush marker bit. */
flush_bits(1);
/* Parse off vbv buffer size. */
get_bits10(vid_stream->vbv_buffer_size);
/* Parse off contrained parameter flag. */
get_bits1(vid_stream->const_param_flag);
/*
* If intra_quant_matrix_flag set, parse off intra quant matrix values.
*/
if (get_bits1(data))
new_matrix(vid_stream->intra_quant_matrix_ptr[1]);
/*
* If non intra quant matrix flag set, parse off non intra quant matrix
* values.
*/
if (get_bits1(data))
{
if(vid_stream->non_intra_default)
{
unsigned short *intra_quant_matrix;
vid_stream->non_intra_quant_matrix_ptr[0] = (short*) malloc(32 * 8*8 * sizeof(short));
clear64words(intra_quant_matrix = vid_stream->non_intra_quant_matrix_ptr[0]);
for(i=1; i<32; i++) vid_stream->non_intra_quant_matrix_ptr[i] = (intra_quant_matrix+=64);
vid_stream->non_intra_default = FALSE;
}
new_matrix(vid_stream->non_intra_quant_matrix_ptr[1]);
}
/* Go to next start code. */
next_start_code();
/* If next start code is extension start code, parse off extension data. */
if ((show_bits32(data)) == EXT_START_CODE) {
flush_bits32;
if (vid_stream->ext_data) {
free(vid_stream->ext_data);
vid_stream->ext_data = NULL;
}
vid_stream->ext_data = get_ext_data();
show_bits32(data);
}
/* If next start code is user start code, parse off user data. */
if (data == USER_START_CODE) {
flush_bits32;
if (vid_stream->user_data) {
free(vid_stream->user_data);
vid_stream->user_data = NULL;
}
vid_stream->user_data = get_ext_data();
}
return PARSE_OK;
}
/*
*--------------------------------------------------------------
*
* ParseGOP --
*
* Parses of group of pictures header from bit stream
* associated with vid_stream.
*
* Results:
* Values in gop header placed into video stream structure.
*
* Side effects:
* Bit stream irreversibly parsed.
*
*--------------------------------------------------------------
*/
static int ParseGOP(VidStream *vid_stream)
{
unsigned int data;
/* Flush group of pictures start code. WWWWWWOOOOOOOSSSSSSHHHHH!!! */
flush_bits32;
/* Parse off drop frame flag. */
get_bits1(vid_stream->group.drop_flag);
/* Parse off hour component of time code. */
get_bits5(vid_stream->group.tc_hours);
/* Parse off minute component of time code. */
get_bits6(vid_stream->group.tc_minutes);
/* Flush marker bit. */
flush_bits(1);
/* Parse off second component of time code. */
get_bits6(vid_stream->group.tc_seconds);
/* Parse off picture count component of time code. */
get_bits6(vid_stream->group.tc_pictures);
/* Parse off closed gop and broken link flags. */
get_bits1(vid_stream->group.closed_gop);
get_bits1(vid_stream->group.broken_link);
/* Goto next start code. */
next_start_code();
/* If next start code is extension data, parse off extension data. */
if ((show_bits32(data)) == EXT_START_CODE) {
flush_bits32;
if (vid_stream->group.ext_data) {
free(vid_stream->group.ext_data);
vid_stream->group.ext_data = NULL;
}
vid_stream->group.ext_data = get_ext_data();
show_bits32(data);
}
/* If next start code is user data, parse off user data. */
if (data == USER_START_CODE) {
flush_bits32;
if (vid_stream->group.user_data) {
free(vid_stream->group.user_data);
vid_stream->group.user_data = NULL;
}
vid_stream->group.user_data = get_ext_data();
}
return PARSE_OK;
}
/*
*--------------------------------------------------------------
*
* ParsePicture --
*
* Parses picture header. Marks picture to be presented
* at particular time given a time stamp.
*
* Results:
* Values from picture header put into video stream structure.
*
* Side effects:
* Bit stream irreversibly parsed.
*
*--------------------------------------------------------------
*/
static int ParsePicture(VidStream *vid_stream, TimeStamp time_stamp)
{
unsigned int data;
int i;
/* Flush header start code. */
flush_bits32;
/* Parse off temporal reference. */
get_bits10(vid_stream->picture.temp_ref);
/* Parse of picture type. */
get_bits3(vid_stream->picture.code_type);
if ((vid_stream->picture.code_type == B_TYPE) &&
(No_B_Flag ||
(vid_stream->past == NULL) ||
(vid_stream->future == NULL)))
return SKIP_PICTURE;
if ((vid_stream->picture.code_type == P_TYPE) &&
(No_P_Flag || (vid_stream->future == NULL)))
return SKIP_PICTURE;
#ifdef ANALYSIS
StartTime();
stat_a[0].frametype = vid_stream->picture.code_type;
stat_a[0].number = 1;
stat_a[0].totsize = 45;
pictureSizeCount = bitCountRead();
#endif
/* Parse off vbv buffer delay value. */
get_bits16(vid_stream->picture.vbv_delay);
/* If P or B type frame... */
if ((vid_stream->picture.code_type == 2) || (vid_stream->picture.code_type == 3)) {
/* Parse off forward vector full pixel flag. */
get_bits1(vid_stream->picture.full_pel_forw_vector);
/* Parse of and decode forw_r_code into forw_r_size and forw_f. */
get_bits3(vid_stream->picture.forw_r_size) - 1;
vid_stream->picture.forw_f = (1 << vid_stream->picture.forw_r_size);
}
/* If B type frame... */
if (vid_stream->picture.code_type == 3) {
/* Parse off back vector full pixel flag. */
get_bits1(vid_stream->picture.full_pel_back_vector);
/* Parse off and decode back_r_code into back_r_size and back_f. */
get_bits3(vid_stream->picture.back_r_size) - 1;
vid_stream->picture.back_f = (1 << vid_stream->picture.back_r_size);
}
/* Get extra bit picture info. */
if (vid_stream->picture.extra_info) {
free(vid_stream->picture.extra_info);
vid_stream->picture.extra_info = NULL;
}
vid_stream->picture.extra_info = get_extra_bit_info();
/* Goto next start code. */
next_start_code();
/* If start code is extension start code, parse off extension data. */
if ((show_bits32(data)) == EXT_START_CODE) {
flush_bits32;
if (vid_stream->picture.ext_data) {
free(vid_stream->picture.ext_data);
vid_stream->picture.ext_data = NULL;
}
vid_stream->picture.ext_data = get_ext_data();
show_bits32(data);
}
/* If start code is user start code, parse off user data. */
if (data == USER_START_CODE) {
flush_bits32;
if (vid_stream->picture.user_data) {
free(vid_stream->picture.user_data);
vid_stream->picture.user_data = NULL;
}
vid_stream->picture.user_data = get_ext_data();
}
/* Find a pict image structure in ring buffer not currently locked. */
i = 0;
while (vid_stream->ring[i]->locked != 0) {
if (++i >= RING_BUF_SIZE) {
perror("Fatal error. Ring buffer full.");
exit(1);
}
}
/* Set current pict image structure to the one just found in ring. */
vid_stream->current = vid_stream->ring[i];
/* Set time stamp. */
vid_stream->current->show_time = time_stamp;
/* Reset past macroblock address field. */
vid_stream->mblock.past_mb_addr = -1;
return PARSE_OK;
}
/*
*--------------------------------------------------------------
*
* ParseSlice --
*
* Parses off slice header.
*
* Results:
* Values found in slice header put into video stream structure.
*
* Side effects:
* Bit stream irreversibly parsed.
*
*--------------------------------------------------------------
*/
static int ParseSlice(VidStream *vid_stream)
{
/* Flush slice start code. */
flush_bits(24);
/* Parse off slice vertical position. */
get_bits8(vid_stream->slice.vert_pos);
/* Parse off quantization scale. */
get_bits5(vid_stream->slice.quant_scale);
/* Parse off extra bit slice info. */
if (vid_stream->slice.extra_info) {
free(vid_stream->slice.extra_info);
vid_stream->slice.extra_info = NULL;
}
vid_stream->slice.extra_info = get_extra_bit_info();
/* Reset past intrablock address. */
vid_stream->mblock.past_intra_addr = -2;
/* Reset previous recon motion vectors. */
vid_stream->mblock.recon_right_for_prev = 0;
vid_stream->mblock.recon_down_for_prev = 0;
vid_stream->mblock.recon_right_back_prev = 0;
vid_stream->mblock.recon_down_back_prev = 0;
/* Reset macroblock address. */
vid_stream->mblock.mb_address = ((short)(vid_stream->slice.vert_pos - 1) * (short)vid_stream->mb_width) - 1;
/* Reset past dct dc y, cr, and cb values. */
vid_stream->block.dct_dc_y_past = 1024;
vid_stream->block.dct_dc_cr_past = 1024;
vid_stream->block.dct_dc_cb_past = 1024;
return PARSE_OK;
}
/*
*--------------------------------------------------------------
*
* ParseMacroBlock --
*
* Parseoff macroblock. Reconstructs DCT values. Applies
* inverse DCT, reconstructs motion vectors, calculates and
* set pixel values for macroblock in current pict image
* structure.
*
* Results:
* Here's where everything really happens. Welcome to the
* heart of darkness.
*
* Side effects:
* Bit stream irreversibly parsed off.
*
*--------------------------------------------------------------
*/
static int ParseMacroBlock(VidStream *vid_stream)
{
int addr_incr, mask, i;
int recon_right_for, recon_down_for, recon_right_back, recon_down_back, zero_block_flag;
int mb_data;
#ifdef ANALYSIS
mbSizeCount = bitCountRead();
#endif
/*
* Parse off macroblock address increment and add to macroblock address.
*/
do {
DecodeMBAddrInc(addr_incr);
if (addr_incr == MB_ESCAPE) {
vid_stream->mblock.mb_address += 33;
addr_incr = MB_STUFFING;
}
} while (addr_incr == MB_STUFFING);
vid_stream->mblock.mb_address += addr_incr;
if (vid_stream->mblock.mb_address > ((short)vid_stream->mb_height * (short)vid_stream->mb_width - 1))
return SKIP_TO_START_CODE;
/*
* If macroblocks have been skipped, process skipped macroblocks.
*/
if (vid_stream->mblock.mb_address - vid_stream->mblock.past_mb_addr > 1) {
if (vid_stream->picture.code_type == P_TYPE)
ProcessSkippedPFrameMBlocks(vid_stream);
else if (vid_stream->picture.code_type == B_TYPE)
ProcessSkippedBFrameMBlocks(vid_stream);
}
/* Set past macroblock address to current macroblock address. */
vid_stream->mblock.past_mb_addr = vid_stream->mblock.mb_address;
/* Based on picture type decode macroblock type. */
switch (vid_stream->picture.code_type) {
case I_TYPE:
DecodeMBTypeI(mb_data, vid_stream->mblock.mb_intra);
break;
case P_TYPE:
DecodeMBTypeP(mb_data, vid_stream->mblock.mb_intra);
break;
case B_TYPE:
DecodeMBTypeB(mb_data, vid_stream->mblock.mb_intra);
break;
}
/* If quantization flag set, parse off new quantization scale. */
if (mb_data&MB_quant) {
get_bits5(vid_stream->slice.quant_scale);
}
/* If forward motion vectors exist... */
if (mb_data&MB_motion_forw) {
/* Parse off and decode horizontal forward motion vector. */
DecodeMotionVectors(vid_stream->mblock.motion_h_forw_code);
/* If horiz. forward r data exists, parse off. */
if ((vid_stream->picture.forw_f != 1) && (vid_stream->mblock.motion_h_forw_code != 0)) {
get_bitsn(vid_stream->picture.forw_r_size, vid_stream->mblock.motion_h_forw_r);
}
/* Parse off and decode vertical forward motion vector. */
DecodeMotionVectors(vid_stream->mblock.motion_v_forw_code);
/* If vert. forw. r data exists, parse off. */
if ((vid_stream->picture.forw_f != 1) && (vid_stream->mblock.motion_v_forw_code != 0)) {
get_bitsn(vid_stream->picture.forw_r_size, vid_stream->mblock.motion_v_forw_r);
}
}
/* If back motion vectors exist... */
if (mb_data&MB_motion_back) {
/* Parse off and decode horiz. back motion vector. */
DecodeMotionVectors(vid_stream->mblock.motion_h_back_code);
/* If horiz. back r data exists, parse off. */
if ((vid_stream->picture.back_f != 1) && (vid_stream->mblock.motion_h_back_code != 0)) {
get_bitsn(vid_stream->picture.back_r_size, vid_stream->mblock.motion_h_back_r);
}
/* Parse off and decode vert. back motion vector. */
DecodeMotionVectors(vid_stream->mblock.motion_v_back_code);
/* If vert. back r data exists, parse off. */
if ((vid_stream->picture.back_f != 1) && (vid_stream->mblock.motion_v_back_code != 0)) {
get_bitsn(vid_stream->picture.back_r_size, vid_stream->mblock.motion_v_back_r);
}
}
#ifdef ANALYSIS
if (vid_stream->mblock.mb_intra) {
stat_a[0].i_mbnum++;
mbCBPPtr = stat_a[0].i_mbcbp;
mbCoeffPtr = stat_a[0].i_mbcoeff;
mbSizePtr = &(stat_a[0].i_mbsize);
} else if ((mb_data&(MB_motion_back | MB_motion_forw)) == (MB_motion_back | MB_motion_forw)) {
stat_a[0].bi_mbnum++;
mbCBPPtr = stat_a[0].bi_mbcbp;
mbCoeffPtr = stat_a[0].bi_mbcoeff;
mbSizePtr = &(stat_a[0].bi_mbsize);
} else if (mb_data&MB_motion_back) {
stat_a[0].b_mbnum++;
mbCBPPtr = stat_a[0].b_mbcbp;
mbCoeffPtr = stat_a[0].b_mbcoeff;
mbSizePtr = &(stat_a[0].b_mbsize);
} else {
stat_a[0].p_mbnum++;
mbCBPPtr = stat_a[0].p_mbcbp;
mbCoeffPtr = stat_a[0].p_mbcoeff;
mbSizePtr = &(stat_a[0].p_mbsize);
}
#endif
/* If mblock pattern flag set, parse and decode CBP (code block pattern). */
if (mb_data&MB_pattern) {
DecodeCBP(vid_stream->mblock.cbp);
} else /* Otherwise, set CBP to zero. */
vid_stream->mblock.cbp = 0;
#ifdef ANALYSIS
mbCBPPtr[vid_stream->mblock.cbp]++;
#endif
/* Reconstruct motion vectors depending on picture type. */
if (vid_stream->picture.code_type == P_TYPE) {
/*
* If no forw motion vectors, reset previous and current vectors to 0.
*/
if (!(mb_data&MB_motion_forw)) {
recon_right_for = 0;
recon_down_for = 0;
vid_stream->mblock.recon_right_for_prev = 0;
vid_stream->mblock.recon_down_for_prev = 0;
}
/*
* Otherwise, compute new forw motion vectors. Reset previous vectors to
* current vectors.
*/
else {
ComputeForwVector(&recon_right_for, &recon_down_for);
}
}
if (vid_stream->picture.code_type == B_TYPE) {
/* Reset prev. and current vectors to zero if mblock is intracoded. */
if (vid_stream->mblock.mb_intra) {
vid_stream->mblock.recon_right_for_prev = 0;
vid_stream->mblock.recon_down_for_prev = 0;
vid_stream->mblock.recon_right_back_prev = 0;
vid_stream->mblock.recon_down_back_prev = 0;
} else {
/* If no forw vectors, current vectors equal prev. vectors. */
if (!(mb_data&MB_motion_forw)) {
recon_right_for = vid_stream->mblock.recon_right_for_prev;
recon_down_for = vid_stream->mblock.recon_down_for_prev;
}
/*
* Otherwise compute forw. vectors. Reset prev vectors to new values.
*/
else {
ComputeForwVector(&recon_right_for, &recon_down_for);
}
/* If no back vectors, set back vectors to prev back vectors. */
if (!(mb_data&MB_motion_back)) {
recon_right_back = vid_stream->mblock.recon_right_back_prev;
recon_down_back = vid_stream->mblock.recon_down_back_prev;
}
/* Otherwise compute new vectors and reset prev. back vectors. */
else {
ComputeBackVector(&recon_right_back, &recon_down_back);
}
/*
* Store vector existance flags in structure for possible skipped
* macroblocks to follow.
*/
if(mb_data<0)
vid_stream->mblock.bpict_past_forw = vid_stream->mblock.bpict_past_back = -1;
else {
vid_stream->mblock.bpict_past_forw = mb_data&MB_motion_forw;
vid_stream->mblock.bpict_past_back = mb_data&MB_motion_back;
}
}
}
/* For each possible block in macroblock. */
if (ditherType == GRAY_DITHER) {
for (mask = 32, i = 0; i < 4; mask >>= 1, i++) {
/* If block exists... */
if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) {
zero_block_flag = 0;
ParseReconBlock(i);
} else
zero_block_flag = 1;
/* If macroblock is intra coded... */
if (vid_stream->mblock.mb_intra) {
ReconIMBlock(vid_stream, i);
} else if ((mb_data&(MB_motion_forw | MB_motion_back)) == (MB_motion_forw | MB_motion_back)) {
ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for,
recon_right_back, recon_down_back, zero_block_flag);
} else if ((mb_data&MB_motion_forw) || (vid_stream->picture.code_type == P_TYPE)) {
ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for,
zero_block_flag);
} else if (mb_data&MB_motion_back) {
ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back,
zero_block_flag);
}
}
/* Kill the Chrominace blocks... */
if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x2)) ParseAwayBlock(4);
if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & 0x1)) ParseAwayBlock(5);
} else {
for (mask = 32, i = 0; i < 6; mask >>= 1, i++) {
/* If block exists... */
if ((vid_stream->mblock.mb_intra) || (vid_stream->mblock.cbp & mask)) {
zero_block_flag = 0;
ParseReconBlock(i);
} else
zero_block_flag = 1;
/* If macroblock is intra coded... */
if (vid_stream->mblock.mb_intra) {
ReconIMBlock(vid_stream, i);
} else if ((mb_data&(MB_motion_forw | MB_motion_back)) == (MB_motion_forw | MB_motion_back)) {
ReconBiMBlock(vid_stream, i, recon_right_for, recon_down_for,
recon_right_back, recon_down_back, zero_block_flag);
} else if ((mb_data&MB_motion_forw) || (vid_stream->picture.code_type == P_TYPE)) {
ReconPMBlock(vid_stream, i, recon_right_for, recon_down_for,
zero_block_flag);
} else if (mb_data&MB_motion_back) {
ReconBMBlock(vid_stream, i, recon_right_back, recon_down_back,
zero_block_flag);
}
}
}
/* If D Type picture, flush marker bit. */
if (vid_stream->picture.code_type == 4) flush_bits(1);
/* If macroblock was intracoded, set macroblock past intra address. */
if (vid_stream->mblock.mb_intra) vid_stream->mblock.past_intra_addr = vid_stream->mblock.mb_address;
#ifdef ANALYSIS
*mbSizePtr += bitCountRead() - mbSizeCount;
#endif
return PARSE_OK;
}
#ifndef MYRECON
/*MR
*--------------------------------------------------------------
*
* ReconIMBlock --
*
* Reconstructs intra coded macroblock.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void ReconIMBlock(VidStream *vid_stream, int bnum)
{
int row, col, row_size;
unsigned char *dest;
row_size = vid_stream->mb_width;
/* Calculate macroblock row and column from address. */
row = vid_stream->mblock.mb_address / row_size;
col = vid_stream->mblock.mb_address % row_size;
/* If block is luminance block... */
if (bnum < 4) {
/* Calculate row and col values for upper left pixel of block. */
row <<= 4;
col <<= 4;
if (bnum > 1) row += 8;
if (bnum & 1) col += 8;
/* Set dest to luminance plane of current pict image. */
dest = vid_stream->current->luminance;
/* Establish row size. */
row_size *= 16;
}
/* Otherwise if block is Cr block... */
else if (bnum == 4) {
/* Set dest to Cr plane of current pict image. */
dest = vid_stream->current->Cr;
/* Establish row size. */
row_size <<= 3;
/* Calculate row,col for upper left pixel of block. */
row <<= 3;
col <<= 3;
}
/* Otherwise block is Cb block, and ... */
else {
/* Set dest to Cb plane of current pict image. */
dest = vid_stream->current->Cb;
/* Establish row size. */
row_size <<= 3;
/* Calculate row,col for upper left pixel value of block. */
row <<= 3;
col <<= 3;
}
/*
* For each pixel in block, set to cropped reconstructed value from inverse dct.
*/
IM_reconstruct(dest + row * row_size + col, &vid_stream->block.dct_recon[0][0], row_size);
}
/* MR
*--------------------------------------------------------------
*
* ReconPMBlock --
*
* Reconstructs forward predicted macroblocks.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void ReconPMBlock(VidStream *vid_stream, int bnum, int recon_right_for, int recon_down_for, int zflag)
{
int row, col, row_size;
unsigned char *dest, *past, *rindex2;
int right_half_for, down_half_for;
row_size = vid_stream->mb_width;
/* Calculate macroblock row and column from address. */
row = vid_stream->mblock.mb_address / row_size;
col = vid_stream->mblock.mb_address % row_size;
if (bnum < 4) {
/* Calculate right_for, down_for motion vectors. */
right_half_for = recon_right_for & 0x1;
down_half_for = recon_down_for & 0x1;
recon_right_for >>= 1;
recon_down_for >>= 1;
/* Set dest to luminance plane of current pict image. */
dest = vid_stream->current->luminance;
if (vid_stream->picture.code_type == B_TYPE) {
if (vid_stream->past) past = vid_stream->past->luminance;
} else {
/* Set predicitive frame to current future frame. */
if (vid_stream->future) past = vid_stream->future->luminance;
}
/* Establish row size. */
row_size <<= 4;
/* Calculate row,col of upper left pixel in block. */
row <<= 4;
col <<= 4;
if (bnum > 1) row += 8;
if (bnum & 1) col += 8;
}
/* Otherwise, block is NOT luminance block, ... */
else {
/* Construct motion vectors. */
right_half_for = (recon_right_for & 0x2)>>1;
down_half_for = recon_down_for & 0x2;
recon_right_for >>= 2;
recon_down_for >>= 2;
/* Establish row size. */
row_size <<= 3;
/* Calculate row,col of upper left pixel in block. */
row <<= 3;
col <<= 3;
/* If block is Cr block... */
if (bnum == 4) {
/* Set dest to Cr plane of current pict image. */
dest = vid_stream->current->Cr;
if (vid_stream->picture.code_type == B_TYPE) {
if (vid_stream->past) past = vid_stream->past->Cr;
} else {
if (vid_stream->future) past = vid_stream->future->Cr;
}
}
/* Otherwise, block is Cb block... */
else {
/* Set dest to Cb plane of current pict image. */
dest = vid_stream->current->Cb;
if (vid_stream->picture.code_type == B_TYPE) {
if (vid_stream->past) past = vid_stream->past->Cb;
} else {
if (vid_stream->future) past = vid_stream->future->Cb;
}
}
}
/* For each pixel in block... */
dest += ((short)row * (short)row_size) + col;
past += (short)(row + recon_down_for) * (short)row_size + col + recon_right_for;
/*
* Calculate predictive pixel value based on motion vectors and copy to
* dest plane.
*/
if ((!down_half_for) && (!right_half_for)) {
if (!zflag)
BMcm_reconstruct(dest, past, &(vid_stream->block.dct_recon[0][0]), row_size);
else
BM_reconstruct(dest, past, row_size);
} else {
rindex2 = past + right_half_for + (down_half_for?row_size:0);
if (!zflag)
BIMcm_reconstruct(dest, past, rindex2, &(vid_stream->block.dct_recon[0][0]), row_size);
else
BIM_reconstruct(dest, past, rindex2, row_size);
}
}
/* MR
*--------------------------------------------------------------
*
* ReconBMBlock --
*
* Reconstructs back predicted macroblocks.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void ReconBMBlock(VidStream *vid_stream, int bnum, int recon_right_back, int recon_down_back, int zflag)
{
int row, col, row_size;
unsigned char *dest, *future, *rindex2;
int right_half_back, down_half_back;
row_size = vid_stream->mb_width;
/* Calculate macroblock row and column from address. */
row = vid_stream->mblock.mb_address / row_size;
col = vid_stream->mblock.mb_address % row_size;
/* If block is luminance block... */
if (bnum < 4) {
/* Calculate right_back, down_back motion vectors. */
right_half_back = recon_right_back & 0x1;
down_half_back = recon_down_back & 0x1;
recon_right_back >>= 1;
recon_down_back >>= 1;
/* Set dest to luminance plane of current pict image. */
dest = vid_stream->current->luminance;
/* If future frame exists, set future to luminance plane of future frame. */
if (vid_stream->future) future = vid_stream->future->luminance;
/* Establish row size. */
row_size <<= 4;
/* Calculate row,col of upper left pixel in block. */
row <<= 4;
col <<= 4;
if (bnum > 1) row += 8;
if (bnum & 1) col += 8;
}
/* Otherwise, block is NOT luminance block, ... */
else {
/* Construct motion vectors. */
right_half_back = (recon_right_back & 0x2)>>1; /* used as integer down there */
down_half_back = recon_down_back & 0x2;
recon_right_back >>= 2;
recon_down_back >>= 2;
/* Establish row size. */
row_size <<= 3;
/* Calculate row,col of upper left pixel in block. */
row <<= 3;
col <<= 3;
/* If block is Cr block... */
if (bnum == 4) {
/* Set dest to Cr plane of current pict image. */
dest = vid_stream->current->Cr;
/* If future frame exists, set future to Cr plane of future image. */
if (vid_stream->future) future = vid_stream->future->Cr;
}
/* Otherwise, block is Cb block... */
else {
/* Set dest to Cb plane of current pict image. */
dest = vid_stream->current->Cb;
/* If future frame exists, set future to Cb plane of future frame. */
if (vid_stream->future) future = vid_stream->future->Cb;
}
}
/* For each pixel in block do... */
dest += ((short)row * (short)row_size) + col;
future += (short)(row + recon_down_back) * (short)row_size + col + recon_right_back;
if ((!right_half_back) && (!down_half_back)) {
if (!zflag)
BMcm_reconstruct(dest, future, &(vid_stream->block.dct_recon[0][0]), row_size);
else
BM_reconstruct(dest, future, row_size);
} else {
rindex2 = future + right_half_back + (down_half_back?row_size:0);
if (!zflag)
BIMcm_reconstruct(dest, future, rindex2, &(vid_stream->block.dct_recon[0][0]), row_size);
else
BIM_reconstruct(dest, future, rindex2, row_size);
}
}
/* MR
*--------------------------------------------------------------
*
* ReconBiMBlock --
*
* Reconstructs bidirectionally predicted macroblocks.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void ReconBiMBlock(VidStream *vid_stream, int bnum,
int forw_col_start, int forw_row_start,
int back_col_start, int back_row_start,
int zflag)
{
int row, col, row_size;
unsigned char *dest, *past, *future;
row_size = vid_stream->mb_width;
/* Calculate macroblock row and column from address. */
row = vid_stream->mblock.mb_address / row_size;
col = vid_stream->mblock.mb_address % row_size;
/* If block is luminance block... */
if (bnum < 4) {
/* Set dest to luminance plane of current pict image. */
dest = vid_stream->current->luminance;
/* If past frame exists, set past to luminance plane of past frame. */
if (vid_stream->past) past = vid_stream->past->luminance;
/*If future frame exists, set future to luminance plane of future frame. */
if (vid_stream->future) future = vid_stream->future->luminance;
/* Establish row size. */
row_size <<= 4;
/* Calculate row,col of upper left pixel in block. */
row <<= 4;
col <<= 4;
if (bnum > 1) row += 8;
if (bnum & 1) col += 8;
forw_col_start = (forw_col_start>>1) + col;
forw_row_start = (forw_row_start>>1) + row;
back_col_start = (back_col_start>>1) + col;
back_row_start = (back_row_start>>1) + row;
}
/* Otherwise, block is NOT luminance block, ... */
else {
/* Establish row size. */
row_size <<= 3;
/* Calculate row,col of upper left pixel in block. */
row <<= 3;
col <<= 3;
forw_col_start = (forw_col_start>>2) + col;
forw_row_start = (forw_row_start>>2) + row;
back_col_start = (back_col_start>>2) + col;
back_row_start = (back_row_start>>2) + row;
/* If block is Cr block... */
if (bnum == 4) {
/* Set dest to Cr plane of current pict image. */
dest = vid_stream->current->Cr;
/* If past frame exists, set past to Cr plane of past image. */
if (vid_stream->past) past = vid_stream->past->Cr;
/* If future frame exists, set future to Cr plane of future image. */
if (vid_stream->future) future = vid_stream->future->Cr;
}
/* Otherwise, block is Cb block... */
else {
/* Set dest to Cb plane of current pict image. */
dest = vid_stream->current->Cb;
/* If past frame exists, set past to Cb plane of past frame. */
if (vid_stream->past) past = vid_stream->past->Cb;
/* If future frame exists, set future to Cb plane of future frame. */
if (vid_stream->future) future = vid_stream->future->Cb;
}
}
dest += (short)row * (short)row_size + col;
past += (short)forw_row_start * (short)row_size + forw_col_start;
future += (short)back_row_start * (short)row_size + back_col_start;
if (!zflag)
BIMcm_reconstruct(dest, past, future, &(vid_stream->block.dct_recon[0][0]), row_size);
else
BIM_reconstruct(dest, past, future, row_size);
}
#endif
/* MR
*--------------------------------------------------------------
*
* ProcessSkippedPFrameMBlocks --
*
* Processes skipped macroblocks in P frames.
*
* Results:
* Calculates pixel values for luminance, Cr, and Cb planes
* in current pict image for skipped macroblocks.
*
* Side effects:
* Pixel values in pict image changed.
*
*--------------------------------------------------------------
*/
static void ProcessSkippedPFrameMBlocks(VidStream *vid_stream)
{
int row_size, row, col, addr, off;
/* Calculate row sizes for luminance and Cr/Cb macroblock areas. */
row_size = vid_stream->mb_width << 4;
/* For each skipped macroblock, do... */
addr = vid_stream->mblock.past_mb_addr + 1;
row = (addr / vid_stream->mb_width)<<4;
col = (addr % vid_stream->mb_width)<<4;
for (; addr < vid_stream->mblock.mb_address; addr++, col+=16) {
/* Calculate macroblock row and col. */
if(col>=row_size) col=0, row+=16;
/* For each row in macroblock luminance plane... */
off = ((short)row * (short)row_size);
PMB1_reconstruct(vid_stream->current->luminance + off + col,
vid_stream->future->luminance + off + col,
row_size >> 2);
/* For each row in Cr, and Cb planes... */
off >>= 2;
off += (col>>1);
PMB2_reconstruct(vid_stream->current->Cr + off,
vid_stream->current->Cb + off,
vid_stream->future->Cr + off,
vid_stream->future->Cb + off,
row_size >> 3);
}
vid_stream->mblock.recon_right_for_prev = 0;
vid_stream->mblock.recon_down_for_prev = 0;
}
/* MR
*--------------------------------------------------------------
*
* ProcessSkippedBFrameMBlocks --
*
* Processes skipped macroblocks in B frames.
*
* Results:
* Calculates pixel values for luminance, Cr, and Cb planes
* in current pict image for skipped macroblocks.
*
* Side effects:
* Pixel values in pict image changed.
*
*--------------------------------------------------------------
*/
static void ProcessSkippedBFrameMBlocks(VidStream *vid_stream)
{
int row_size, half_row, row, col, ccol, crow;
int right_half_for, down_half_for, c_right_half_for, c_down_half_for;
int right_half_back, down_half_back, c_right_half_back, c_down_half_back;
int addr;
int recon_right_for, recon_down_for, recon_right_back, recon_down_back;
int c_right_for, c_down_for, c_right_back, c_down_back;
unsigned char forw_lum[256];
unsigned char forw_cr[64], forw_cb[64];
unsigned char back_lum[256], back_cr[64], back_cb[64];
int row_incr, half_row_incr;
int h;
char *lum;
/* Calculate row sizes for luminance and Cr/Cb macroblock areas. */
row_size = vid_stream->mb_width << 4;
half_row = row_size >> 1;
row_incr = row_size >> 2;
half_row_incr = half_row >> 2;
/* Establish motion vector codes based on full pixel flag. */
recon_right_for = vid_stream->mblock.recon_right_for_prev;
recon_down_for = vid_stream->mblock.recon_down_for_prev;
if (vid_stream->picture.full_pel_forw_vector) {
recon_right_for <<= 1;
recon_down_for <<= 1;
}
recon_right_back = vid_stream->mblock.recon_right_back_prev;
recon_down_back = vid_stream->mblock.recon_down_back_prev;
if (vid_stream->picture.full_pel_back_vector) {
recon_right_back <<= 1;
recon_down_back <<= 1;
}
/* If only one motion vector, do display copy, else do full
calculation.
*/
/* Calculate motion vectors. */
if (vid_stream->mblock.bpict_past_forw) {
right_half_for = recon_right_for & 0x1;
down_half_for = recon_down_for & 0x1;
recon_right_for >>= 1;
recon_down_for >>= 1;
c_right_for = recon_right_for >> 1;
c_down_for = recon_down_for >> 1;
c_right_half_for = recon_right_for & 0x1;
c_down_half_for = recon_down_for & 0x1;
}
if (vid_stream->mblock.bpict_past_back) {
right_half_back = recon_right_back & 0x1;
down_half_back = recon_down_back & 0x1;
recon_right_back >>= 1;
recon_down_back >>= 1;
c_right_back = recon_right_back >> 1;
c_down_back = recon_down_back >> 1;
c_right_half_back = recon_right_back & 0x1;
c_down_half_back = recon_down_back & 0x1;
}
/* For each skipped macroblock, do... */
addr = vid_stream->mblock.past_mb_addr + 1;
row = (addr / vid_stream->mb_width)<<4;
col = (addr % vid_stream->mb_width)<<4;
for (; addr < vid_stream->mblock.mb_address; addr++, col+=16) {
/* Calculate macroblock row and col. */
if(col>=row_size) col=0, row+=16;
/* Calculate upper left pixel row,col for luminance plane. */
crow = row >> 1;
ccol = col >> 1;
/* If forward predicted, calculate prediction values. */
if (vid_stream->mblock.bpict_past_forw) {
ReconSkippedBlock16(vid_stream->past->luminance, forw_lum,
row, col, row_size, recon_right_for, recon_down_for,
right_half_for, down_half_for);
ReconSkippedBlock8(vid_stream->past->Cr, forw_cr, crow, ccol, half_row,
c_right_for, c_down_for, c_right_half_for, c_down_half_for);
ReconSkippedBlock8(vid_stream->past->Cb, forw_cb, crow, ccol, half_row,
c_right_for, c_down_for, c_right_half_for, c_down_half_for);
}
/* If back predicted, calculate prediction values. */
if (vid_stream->mblock.bpict_past_back) {
ReconSkippedBlock16(vid_stream->future->luminance, back_lum,
row, col, row_size, recon_right_back, recon_down_back,
right_half_back, down_half_back);
ReconSkippedBlock8(vid_stream->future->Cr, back_cr, crow, ccol, half_row,
c_right_back, c_down_back,
c_right_half_back, c_down_half_back);
ReconSkippedBlock8(vid_stream->future->Cb, back_cb, crow, ccol, half_row,
c_right_back, c_down_back,
c_right_half_back, c_down_half_back);
}
h = ((short)crow * (short)half_row) + ccol;
lum = (vid_stream->current->luminance + ((short)row * (short)row_size) + col);
if (vid_stream->mblock.bpict_past_forw && !vid_stream->mblock.bpict_past_back) {
PSB1_reconstruct(lum, forw_lum, row_incr);
PSB2_reconstruct(vid_stream->current->Cr + h, vid_stream->current->Cb + h,
forw_cr, forw_cb, half_row_incr);
} else if (vid_stream->mblock.bpict_past_back && !vid_stream->mblock.bpict_past_forw) {
PSB1_reconstruct(lum, back_lum, row_incr);
PSB2_reconstruct(vid_stream->current->Cr + h, vid_stream->current->Cb + h,
back_cr, back_cb, half_row_incr);
} else {
PSB3_reconstruct(lum, forw_lum, back_lum, row_size);
PSB4_reconstruct(vid_stream->current->Cr + h, vid_stream->current->Cb + h,
forw_cr, back_cr, forw_cb, back_cb, half_row);
}
}
}
/* MR
*--------------------------------------------------------------
*
* ReconSkippedBlock -- width 16
*
* Reconstructs predictive block for skipped macroblocks
* in B Frames.
*
* Results:
* No return values.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static
void ReconSkippedBlock16(unsigned char *source, unsigned char *dest, int row, int col, int row_size,
int right, int down, int right_half, int down_half)
{
source += ((short)(row + down) * (short)row_size) + col + right;
if ((!right_half) && (!down_half))
RSB1_reconstruct(dest, source, row_size);
else
RSB2_reconstruct(dest, source, source + right_half + ((short)row_size * (short)down_half), row_size);
}
/* MR
*--------------------------------------------------------------
*
* ReconSkippedBlock -- width 8
*
* Reconstructs predictive block for skipped macroblocks
* in B Frames.
*
* Results:
* No return values.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static
void ReconSkippedBlock8(unsigned char *source, unsigned char *dest, int row, int col, int row_size,
int right, int down, int right_half, int down_half)
{
source += ((short)(row + down) * (short)row_size) + col + right;
if ((!right_half) && (!down_half))
RSB3_reconstruct(dest, source, row_size);
else
RSB4_reconstruct(dest, source, source + right_half + ((short)row_size * (short)down_half), row_size);
}
/*
*--------------------------------------------------------------
*
* DoPictureDisplay --
*
* Converts image from Lum, Cr, Cb to colormap space. Puts
* image in lum plane. Updates past and future frame
* pointers. Dithers image. Sends to display mechanism.
*
* Results:
* Pict image structure locked if displaying or if frame
* is needed as past or future reference.
*
* Side effects:
* Lum plane pummelled.
*
*--------------------------------------------------------------
*/
static void DoPictureDisplay(VidStream *vid_stream)
{
/* init display, if needed */
if(!vid_stream->display_is_initialized)
{
ResizeDisplay(vid_stream->h_size, vid_stream->v_size);
vid_stream->display_is_initialized = TRUE;
}
/* Convert to colormap space and dither. */
DoDitherImage(vid_stream->current->luminance, vid_stream->current->Cr,
vid_stream->current->Cb, vid_stream->current->display,
vid_stream->mb_height <<4, vid_stream->mb_width <<4);
/* Update past and future references if needed. */
if ((vid_stream->picture.code_type == I_TYPE) || (vid_stream->picture.code_type == P_TYPE)) {
if (vid_stream->future == NULL) {
vid_stream->future = vid_stream->current;
vid_stream->future->locked |= FUTURE_LOCK;
} else {
if (vid_stream->past != NULL) {
vid_stream->past->locked &= ~PAST_LOCK;
}
vid_stream->past = vid_stream->future;
vid_stream->past->locked &= ~FUTURE_LOCK;
vid_stream->past->locked |= PAST_LOCK;
vid_stream->future = vid_stream->current;
vid_stream->future->locked |= FUTURE_LOCK;
vid_stream->current = vid_stream->past;
ExecuteDisplay(vid_stream);
}
} else
ExecuteDisplay(vid_stream);
}
/*
*--------------------------------------------------------------
*
* ToggleBFlag --
*
* Called to set no b frame processing flag.
*
* Results:
* No_B_Flag flag is toggled from present value to opposite value.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void ToggleBFlag(void)
{
No_B_Flag ^= 0xffff;
}
/*
*--------------------------------------------------------------
*
* TogglePFlag --
*
* Called to set no p frame processing flag.
*
* Results:
* No_P_Flag flag is toggled from present value to opposite value.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void TogglePFlag(void)
{
No_P_Flag ^= 0xffff;
}